package ExpressOne;

//模拟内存:
//step1:解决就绪态到运行态，运行态到释放内存
//step2:解决pid问题
//step3:解决运行态到阻塞态
//step4:解决阻塞态到就绪态
//step3:解决可视化问题

//明确:在内存运行过程中，只能由运行态释放内存，就绪态和阻塞态不可以
public class MyMemory {

    private int OnlyPID = 0;

    private final int MIN_SIZE = 2;

    private final int MAX_DATA_SIZE;//最大存储空间
    private int nowSize;

    //运行队列，阻塞队列，空闲队列，等待队列
    private final LinkList<ModeNode> running;
    private final LinkList<ModeNode> block;
    private final LinkList<ModeNode> free;
    private final LinkList<ModeNode> ready;
    private final LinkList<Integer> handOn;

    private final int MaxSize;//最大的内存空间
    private int lastLocate;//上一次定位，上一次分配的内存空间

    private final MemoryDisplay memoryShow;

    public MyMemory(int MaxSize, int MAX_DATA_SIZE) {
        running = new LinkList<>();
        block = new LinkList<>();
        free = new LinkList<>();
        ready = new LinkList<>();

        handOn = new LinkList<>();

        this.MaxSize = MaxSize;
        this.MAX_DATA_SIZE=MAX_DATA_SIZE;
        //this.nowSize=MAX_DATA_SIZE;

        lastLocate = 0;
        free.add(new ModeNode(free.getLength(), 0, MaxSize));
        memoryShow = new MemoryDisplay(MaxSize);
    }

    public boolean addToReady(int size) {
        return bestFit(size);
    }

    //最佳适应算法
    private boolean bestFit(int size) {
        int flag = -1;
        int min = this.MaxSize;
        //在空闲区中寻找，找到大小接近的那个区
        for (lastLocate = 0; lastLocate < free.getLength(); lastLocate++) {
            ModeNode t = free.get(lastLocate);
            if (t.size >= size) {
                //找到最小但是接近的那个区
                if (min > t.size - size) {
                    min = t.size - size;
                    flag = lastLocate;
                }
            }
        }
        if (flag == -1) {
            //System.out.println("内存无法分配");
            return false;
        } else {
            if (free.get(flag).size - size > MIN_SIZE) {
                //创建作业
                ModeNode wait = new ModeNode(OnlyPID++, free.get(flag).head, size);
                //把作业添加到等待队列中
                ready.add(wait);
                //等待到执行队列中
                this.readyToRunning();

                //割分空闲分区
                //空闲分区不用分配PID
                ModeNode spite = new ModeNode(free.get(flag).head + size, free.get(flag).size - size);
                //空闲分区删除
                free.remove(free.get(flag));
                free.add(spite);
            } else {
                ModeNode wait = new ModeNode(OnlyPID++, free.get(flag).head, free.get(flag).size);
                //把作业添加到等待队列中
                ready.add(wait);
                free.remove(free.get(flag));

            }
            return true;
        }
    }

    //内存释放
    //在运行队列中，才能释放
    public void interrupt() {
        //free分区的无法释放
        if (running.getLength() == 1) {
            Release(running.remove());
            readyToRunning();
        }
    }

    //释放内存
    //前一个分区为空
    //后一个分区为空
    //前后都为空
    private void Release(ModeNode node) {
        if (node != null) {
            int index1 = -1, index2 = -1;
            ModeNode merge;
            for (int i = 0; i < free.getLength(); i++) {
                ModeNode p = free.get(i);
                //如果前面分区为空，记录当前位置
                if (p.head + p.size == node.head)
                    index1 = i;
                //如果后面分区是空闲的，记录当前位置
                if (node.head + node.size == p.head)
                    index2 = i;
            }

            if (index1 != -1 && index2 == -1) {
                //如果前面是空的，那么直接修改其中的大小值进行合并
                free.get(index1).size += node.size;
            } else if (index1 == -1 && index2 != -1) {
                //如果后面是空的，那么修改头和大小值
                free.get(index2).head = node.head;
                free.get(index2).size += node.size;
            } else if (index1 != -1) {
                //如果前面后面都有，那么就把这三个空间合并
                merge = new ModeNode(Math.min(free.get(index1).head, free.get(index2).head), free.get(index1).size + node.size + free.get(index2).size);
                //错误
                free.remove(free.get(Math.max(index1, index2)));
                free.remove(free.get(Math.min(index1, index2)));
                free.add(merge);
            } else {
                free.add(node);
            }
            //进行合并

        }
    }

    public String showMessage() {
        //显示分区信息
        return "---------------------------\n" +
                "空闲分区:\n" +
                this.show(free.getHead()) +
                "就绪队列:\n" +
                this.show(ready.getHead()) +
                "运行队列:\n" +
                this.show(running.getHead()) +
                "阻塞队列:\n" +
                this.show(block.getHead()) +
                "挂起分区大小总: " + MAX_DATA_SIZE + "  挂起分区现大小: "+nowSize+"\n"+
                "挂起状态程序 " + ":\n" +
                this.show(handOn);
    }

    private String show(LinkList.LinkListNode<ModeNode> node) {
        LinkList.LinkListNode<ModeNode> head = node;
        StringBuilder str = new StringBuilder();
        if (head != null && head.data != null) {
            while (head.next != null && head.next != node) {
                str.append("PID:").append(head.data.pid).append(" Head:").append(head.data.head).append(" Size:").append(head.data.size).append("\n");
                head = head.next;
            }
            str.append("PID:").append(head.data.pid).append(" Head:").append(head.data.head).append(" Size:").append(head.data.size).append("\n");
        }
        return str.toString();
    }


    private String show(LinkList<Integer> node) {
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < node.getLength(); i++) {
            str.append(i + 1).append(" size:").append(node.get(i)).append("\n");
        }
        return str.toString();
    }
    //以下是四种路径状态

    //就绪状态到运行状态
    boolean readyToRunning() {
        //当运行中的东西没了，cpu处于空闲，而就绪队列中有东西，把东西放进去
        if (running.getLength() == 0 && ready.getLength() != 0) {
            running.add(ready.remove());
            return true;
        }
        return false;
    }

    //运行状态到阻塞状态
    boolean runningToBlock() {
        if (running.getLength() != 0) {
            block.add(running.remove());
            this.readyToRunning();
            return true;
        }
        return false;
    }

    //运行状态到就绪状态 时间片轮转
    boolean runningToReady() {
        if (running.getLength() != 0) {
            ready.add(running.remove());
            this.readyToRunning();
            return true;
        }
        return false;
    }

    //阻塞状态到就绪状态
    boolean blockToReady() {
        if (block.getLength() != 0) {
            ready.add(block.remove());
            readyToRunning();
            return true;
        }
        return false;

    }

    //阻塞状态到挂起状态
    boolean blockToHandOn() {
        if (block.getLength() <= 0)
            return false;
        int min = block.get(0).size;
        int index = 0;
        for (int i = 1; i < block.getLength(); i++) {
            ModeNode temp = block.get(i);
            if (min > temp.size) {
                min = temp.size;
                index = i;
            }
        }
        if (min + nowSize > MAX_DATA_SIZE) {
            return false;
        }
        ModeNode temp = block.get(index);
        Release(temp);//释放内存
        block.remove(block.get(index));//除掉这个东西
        handOn.add(min);
        nowSize+=min;
        return true;
    }

    boolean handOnToReady() {
        if (handOn.getLength() <= 0) {
            return false;
        }
        int min = handOn.get(0);
        for (int i = 1; i < handOn.getLength(); i++) {
            int temp = handOn.get(i);
            if (min > temp) {
                min = temp;
            }
        }
        //分配内存
        if (this.addToReady(min)) {
            handOn.remove(min);
            //唤醒之后，放到运行队列中
            this.readyToRunning();

            nowSize-=min;
            return true;
        }
        return false;
    }

    void showColor() {
        //设置内存颜色
        int begin, end;

        memoryShow.setGreenColor(0, MaxSize);
        for (int i = 0; i < running.getLength(); i++) {
            ModeNode n = running.get(i);
            begin = n.head;
            end = n.head + n.size;
            memoryShow.setPinkColor(begin, end);
        }
        for (int i = 0; i < ready.getLength(); i++) {
            ModeNode n = ready.get(i);
            begin = n.head;
            end = n.head + n.size;
            memoryShow.setBlackColor(begin, end);
        }
        for (int i = 0; i < block.getLength(); i++) {
            ModeNode n = block.get(i);
            begin = n.head;
            end = n.head + n.size;
            memoryShow.setRedColor(begin, end);
        }
    }
}

